/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.liquidByte.trafficMustang.server.business;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import org.liquidByte.trafficMustang.server.dataModel.*;
import org.liquidByte.trafficMustang.server.dataModel.enums.DeslocamentoSituacao;
import org.liquidByte.trafficMustang.server.repository.DeslocamentoRepository;
import org.liquidByte.trafficMustang.server.services.*;

/**
 *
 * @author Alexandre
 */
@Stateless
public class DeslocamentoBO implements DeslocamentoService {
    
    @EJB
    private DeslocamentoRepository repository;
    @EJB
    private LoginService loginService;
    @EJB
    private TrechoService trechoService;

    @Override
    public void informar(Deslocamento deslocamento) throws BusinessException {
        Usuario usuario = this.loginService.getUsuario();
        PerfilUsuario perfil = this.loginService.getPerfilUsuario();
        
        if (usuario == null) {
            throw new BusinessException("Usuário não identificado");
        }
        if (perfil != PerfilUsuario.MOTORISTA || usuario.getMotorista() == null) {
            throw new BusinessException("Essa operação pode ser somente feita no perfil motorista");
        }
        
        deslocamento.setDeslcDtPart(new Date());
        deslocamento.setDeslcLotc((short)1);
        deslocamento.setDeslcSitId(DeslocamentoSituacao.EmTransito);
        deslocamento.setMotrId(usuario.getMotorista());
        if (deslocamento.getLocalizacao() == null) {
            throw new BusinessException("É necessário informar a localizacação de destino");
        }
        if (deslocamento.getVeicId() == null) {
            throw new BusinessException("É necessário informar o veículo que será utilizado");
        }
        
        this.repository.persist(deslocamento);
    }

    @Override
    public void cancelar(Deslocamento deslocamento) throws BusinessException {
        Usuario usr = this.loginService.getUsuario();
        if (usr == null || usr.getMotorista() == null || !usr.getMotorista().equals(deslocamento.getMotrId())) {
            throw new BusinessException("Só motorista do deslocamento pode cancela-lo");
        }
        if (deslocamento.getDeslcSitId() == DeslocamentoSituacao.Cancelado ||
            deslocamento.getDeslcSitId() == DeslocamentoSituacao.Finalizado) {
            throw new BusinessException("Somente deslocamento em trânsito podem ser cancelados");
        }
        
        for (Trecho trecho : deslocamento.getTrechoList()) {
            this.trechoService.abortar(trecho);
        }
        
        deslocamento.setDeslcSitId(DeslocamentoSituacao.Cancelado);
        deslocamento.setDeslcLotc((short)0);
        this.repository.persist(deslocamento);
    }

    @Override
    public void finalizar(Deslocamento deslocamento) throws BusinessException {
        Usuario usr = this.loginService.getUsuario();
        if (usr == null || usr.getMotorista() == null || !usr.getMotorista().equals(deslocamento.getMotrId())) {
            throw new BusinessException("Só motorista do deslocamento pode finaliza-lo");
        }
        if (deslocamento.getDeslcSitId() == DeslocamentoSituacao.Cancelado ||
            deslocamento.getDeslcSitId() == DeslocamentoSituacao.Finalizado) {
            throw new BusinessException("Somente deslocamento em trânsito podem ser finalizados");
        }
        for (Trecho trecho : deslocamento.getTrechoList()) {
            if (!this.trechoService.isFinalState(trecho)) {
                throw new BusinessException("Existem trechos não finalizados. Não é possível finalizar.");
            }
        }

        deslocamento.setDeslcSitId(DeslocamentoSituacao.Finalizado);
        deslocamento.setDeslcLotc((short)0);
        deslocamento.setDeslcDtCheg(new Date());
        
        this.repository.persist(deslocamento);
    }

    @Override
    public List<Deslocamento> localizar(Localizacao origem, Localizacao destino)  throws BusinessException {
        if (origem == null) {
            throw new BusinessException("Não foi possível detectar sua localização");
        }
        if (destino == null) {
            throw new BusinessException("Não foi possível detecter o seu destino");
        }
        
        final double DISTANCIA_MAXIMA_ORIGEM = 1;
        final double DISTANCIA_MAXIMO_DESTINO = 1;
        final int TEMPO_MAXIMO_RASTREAMENTO_SEG = 30 *60;
        
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) - TEMPO_MAXIMO_RASTREAMENTO_SEG);
        
        return this.repository.getProximos(origem, DISTANCIA_MAXIMA_ORIGEM, destino, DISTANCIA_MAXIMO_DESTINO, cal.getTime());
    }

    public List<Deslocamento> getPendente(Motorista motorista) {
        return this.repository.get(motorista, DeslocamentoSituacao.EmTransito);
    }

    public boolean existePendencia(Motorista motorista) {
        return this.getPendente(motorista).size() > 0;
    }

    public synchronized void incrementarLotacao(Deslocamento deslc) {
        short lotc = deslc.getDeslcLotc();
        lotc++;
        deslc.setDeslcLotc(lotc);
        this.repository.persist(deslc);
    }

    public synchronized void decrementarLotacao(Deslocamento deslc) {
        short lotc = deslc.getDeslcLotc();
        lotc--;
        deslc.setDeslcLotc(lotc);
        this.repository.persist(deslc);
    }

}
